/**
 * @file   main.cpp
 * @author Pedro Jimenez
 * @date   Fri Nov 14 16:06:58 2008
 * 
 * @brief  Program to read stereo videos in raw format from file and visualize.
 * 
 * 
 */
#include <iostream>
#include <string.h>

#include <stdlib.h>
#include <stdio.h>

#include <sys/time.h>
#include <unistd.h>
#include <sys/select.h>

#include "options.h"
#include <colores.h>
#include "other_functions.h"

#include "read_video_thread.h"
//#include "read_jpegvideo_thread.h"

#define IMAGE_PUNTOS_FILE "image_puntos.txt"
#define SCALE_FACTOR 1.0F


///Names of the openCV image display windows
char window_names[2][100] = { "Left", "Right"};


/**
 * \brief Data needed in the mouse callback function to select points with the mouse
 * 
 */
struct mouse_params_t {
    int n; //!< 0 for left, 1 for right image
    CRead_Video_Thread * reader;
    //CRead_jpegVideo_Thread * reader;
    CvPoint points[4]; //!< Points marked as chessboard corners
    int clicks; //!< Nomber of marked points as chessboard corners
};

void onmouse (int event, int x, int y, int flags, void* param) ;

/// indicates weather to save or not the current frame images
int save;


int main(int argc, char *argv[])
{ 
    int i, j;
    int nimage =1;
    struct mouse_params_t mouse_params[2];
    char buffer[200];
    FILE * puntos=0;
    int numcams=0;

   /// inicialize the command line params
    if (!leer_opciones(argc, argv))
	return 0;

    //objeto que se encarga de leer las imágenes. 
    //se inicializa con un buffer de 100 frames
    //CRead_Video_Thread reader(ini_opt("buffers"));
    CRead_Video_Thread reader(ini_opt("buffers"));

    int wait = ini_opt("speed"), key=0;
    unsigned int next_frame = ini_opt("iniframe");

    ///inicialize the video params
    if (reader.init_params(ini_opts("v"), ini_opts("format"), next_frame))
	return -1;
    reader.set_image_size(ini_opt("width"), ini_opt("height"),
			  ini_opt("offsetx1"), ini_opt("offsety1"),
			  ini_opt("offsetx2"), ini_opt("offsety2") );
    
    //lanza el hilo de lectura de las imágenes
    if (!reader.start())
    {
	printf("error en la lectura de los videos.\n");
	return -1;
    }

    
    numcams = reader.numcams();
    for (i=0; i<numcams; i++)
    {
	cvNamedWindow(window_names[i], 0);
	mouse_params[i].n = i;
	mouse_params[i].reader = &reader;//.get_cloneimage(i);
	mouse_params[i].clicks =0;
	cvSetMouseCallback(window_names[i], onmouse, &mouse_params[i]);
    } 

    ///main visualizing loop
    do
    {
	///get next image from the buffer
	fflush(stdout);
	Cstereo_IplImage *img = reader.consumer();
	//Cjpeg_IplImage *img = reader.consumer();
	if (!img) //check if there are more frames
	    break;

	/// and display
	for (i=0; i<numcams; i++)
	    cvShowImage(window_names[i], reader.img(i));

	//read keyboard
	while ((key=bucle_cvWaitKey(&wait)) > 0)
	    ;

	if (save)
	{
	    save =0;
	    if (mouse_params[0].clicks==4 && mouse_params[1].clicks == 4)
	    {
		if (!puntos)
		{
		    puntos = fopen(IMAGE_PUNTOS_FILE, "w");
		    fprintf(puntos, "%f SCALE_FACTOR\n", SCALE_FACTOR);
		}

		sprintf(buffer, "image_left_%03d.jpg", nimage);
		cvSaveImage(buffer, reader.img(0));
		sprintf(buffer, "image_right_%03d.jpg", nimage);
		cvSaveImage(buffer, reader.img(1));
		printf("Saved image %d\n", nimage);

		for (i=0; i<2; i++)
		    for (j=0; j<4; j++)
		    {
			fprintf(puntos, "%d ", mouse_params[i].points[j].x);
			fprintf(puntos, "%d ", mouse_params[i].points[j].y);
		    }
		fprintf(puntos, "%d \n", img->head[0]->nframe);
		fflush(puntos);
		nimage++;
	    }
	}
	mouse_params[0].clicks = 0;
	mouse_params[1].clicks = 0;


    } while (key >= 0);
    
    fflush(stdout);
    if (puntos)
	fclose(puntos);
    return 0;
}



/** 
 * \brief Mouse callback function. Performs the chessboard corners selection
 * 
 * This callback performs the chessboard corners selection, so it can be saved in a file for further 
 * in a calibration proccess in Matlab.
 *
 * @param event Indicates the events that triggered the callback
 * @param x Position of the mouse
 * @param y Position of the mouse
 * @param flags State of the mouse buttons
 * @param param Pointer to a struct mouse_params_t, with chessboard corners selection process info
 */
void onmouse (int event, int x, int y, int flags, void* param) 
{
    struct mouse_params_t *p = (struct mouse_params_t *)param;
    //printf("Image %d, event %d, flag %d, pos:%3d,%3d\n", p->n, event, flags, x, y);
    int i;

    if (event == 1 && p->clicks < 4)
    {
	if (p->clicks == 0)
	    p->reader->cloneimages(p->n);
	save =1;
	p->points[p->clicks] = cvPoint(x, y);
	p->clicks ++;

	IplImage * img = p->reader->get_cloneimage(p->n);
	for (i=1; i<p->clicks; i++)
	{
	    cvLine(img, p->points[i-1], p->points[i], CV_RGB(255,0,0), 3);
	}
	cvShowImage(window_names[p->n], img);
	cvWaitKey(10);
    }
    else if (event == 2)
	p->clicks = 0;
	
}

/** 
 * @brief command line options
 */
struct option2 mainopts2[]= {
    {{"v", 1, NULL, OPT_VAL_IS_CHAR}, 0, "", 
     "Video to process"},
    {{"speed", 1, NULL, OPT_VAL_IS_INT}, 0, "", 
     "tIndicates de inicial display speed: 1: fast, 9: slow, 0:stooped(default)"},
    {{"format", 1, NULL, OPT_VAL_IS_CHAR}, 0, "", 
     "format = [raw | ra2 | avi]: Tells the format of the video"},
    {{"cam", 0, NULL, true}, false, "", 
     "Capture de video from the cameras"},
    {{"calibrar", 0, NULL, true}, false, "", 
     "Inicia la recolección automática de datos para la calibración con matlab."},
    {{"calibrar2", 0, NULL, true}, false, "", 
     "Inicia la marcación manual de datos para la calibración con matlab."},
    {{"review", 0, NULL, true}, false, "", 
     "repasa los datos de la calibración"},
    {{"nodisp", 0, NULL, true}, false, "",
     "No muestra las imágenes por pantalla."},
    {{"iniframe", 1, NULL, OPT_VAL_IS_INT}, 0, "",
     "inidica el frame de inicio"},
    {{"buffers", 1, NULL, OPT_VAL_IS_INT}, 200, "",
     "Numero de buffers a usar para la lectura del disco de los videos."},
    {{"width", 1, NULL, OPT_VAL_IS_INT}, 0, "", 
     "Ancho (x) de la imágen, en píxeles. 0 para valor predeterminado del video"},
    {{"height", 1, NULL, OPT_VAL_IS_INT}, 0, "", 
     "Alto (y) de la imágen, en píxeles. 0 para valor predeterminado del video"},
    {{"offsetx1", 1, NULL, OPT_VAL_IS_INT}, -1, "", 
     "desplazamiento horizontal (en x)  de la imágen de la cámara izquierda, en píxeles. 0 centrar la ROI"},
    {{"offsety1", 1, NULL, OPT_VAL_IS_INT}, -1, "", 
     "desplazamiento vertical (en y)  de la imágen de la cámara izquierda, en píxeles. 0 centrar la ROI"},
    {{"offsetx2", 1, NULL, OPT_VAL_IS_INT}, -1, "", 
     "desplazamiento horizontal (en x)  de la imágen de la cámara derecha, en píxeles. 0 centrar la ROI"},
    {{"offsety2", 1, NULL, OPT_VAL_IS_INT}, -1, "", 
     "desplazamiento vertical (en y)  de la imágen de la cámara derecha, en píxeles. 0 centrar la ROI"},

    {{"options", 0, NULL, true}, false, "", 
     "Imprime las opciones de configuracion del programa"},
    {{"h", 0, NULL, true}, false, "", 
     "Muestra las opciones que se pueden indicar por línea de comandos"},
    {{"help", 0, NULL, true}, false, "", 
     "Muestra esta ventana de ayuda"},
    {{NULL, 0, NULL, 0}, 0, "", 
     ""}
};
